問題解説: Docker 筆記

1問目

問題文

以下のDockerコンテナに関する説明のうち、正しいものを選択してください。

a. Dockerコンテナ内で動かすことができるプロセス数の上限は1である
b. Dockerコンテナ内部のUIDを0以外に指定できる
c. Dockerコンテナではデフォルトでinit(systemdなど)が実行される
d. “scratch”と呼ばれるイメージを使うと、ホストのOSと同じOSが入ったDockerコンテナを起動できる

解説

この問題はDockerコンテナに関する知識問題でした。

a. Dockerコンテナ内で動かすことができるプロセス数の上限は1である

誤りです。Dockerコンテナ内ではulimitなどに違反しない限りいくつでもプロセスを立ち上げられます。(=フォークできる)

b. Dockerコンテナ内部のUIDを0以外に指定できる

正解です。Dockerコンテナの中では、root以外にも新しいユーザー追加して利用することができます。

c. Dockerコンテナではデフォルトでinit(systemdなど)が実行される

誤りです。Dockerコンテナの場合、通常initは起動せず単体のプロセスが実行されます。LXCなどでは、デフォルトでinitが実行されます。

d. “scratch”と呼ばれるイメージを使うと、ホストのOSと同じOSが入ったDockerコンテナを起動できる

誤りです。”scratch”は何も入っていない真っ白なイメージです。golangのバイナリを置いたり、マルチステージビルドと組み合わせて活用すると、イメージの容量を削減できます。

回答

b. Dockerコンテナ内部のUIDを0以外に指定できる

採点基準

正解の選択肢をすべて選んだ場合にのみ満点の70点を与えました。

講評

49チーム中、回答率は95%(47チーム)、正答率は65%(32チーム)でした。

Dockerを触る上では欠かせない基礎知識なので、ぜひ身につけてもらいたいなと思いました。

また、Docker以外のコンテナ技術では正しい選択肢を織り交ぜたので、自分で比較しながら他のコンテナも触ってもらえると嬉しいです。

2問目

問題文

Docker Swarm に関する以下の記述のうち、正しいものを選択してください。(複数選択可)

a. Docker Swarm ではサービスのイメージタグに latest を指定すると、常に最新のイメージを用いてコンテナがデプロイされる
b. Docker Swarm では標準で IPIP トンネリングを用いてノードを跨いだコンテナ間の通信を提供する
c. Docker Swarm ではマネージャー(クラスタを管理するノード)と非マネージャー(コンテナを実行するノード)の役割を同一のホストに割り当てることができる
d. Docker Swarm では非マネージャーの数より多い数のレプリカを指定したサービスを作成できる

概要

この問題は コンテナに関するツールである Docker において、複数台のノードでのクラスタリング機能を提供する Docker の Swarm mode に関する知識問題です。

クラスタリング/オーケストレーション環境としては他にも Kubernetes や Mesos が有名ですが、ここでは Docker 本体にバンドルされている Docker Swarm を対象としました。

この機能を使ったことがある人はほとんどいないという想定であったため、ドキュメントを読んで解答ができるようにしています。

解説

a. Docker Swarm ではサービスのイメージタグに latest を指定すると、常に最新のイメージを用いてコンテナがデプロイされる

誤りです。Docker Swarm では、サービスのコンテナ数を指定された値に保つように維持しますが、このとき、ノードに latest タグが付与された古いイメージがあるときには、最新のイメージを pull せずにそれを用いて起動します。

latest タグは、コンテナレジストリ上で最新のイメージを参照するためにしばしば用いられます。

より具体的な例を上げて説明しましょう。Docker Hub の ruby イメージでは、 Ruby 2.5.1 のリリース後に ruby:latestruby:2.5.0 ではなく ruby:2.5.1 と等しくなるように変更されました。(ソース)
このとき、 Ruby 2.5.1 のリリース前に ruby:latest イメージを pull していたノードでは、ruby:latest イメージとして Ruby 2.5.0 のイメージを保持しているため、 Docker Hub の ruby:latest が更新されても新たに pull をし直すことはありません。
一方、それまで ruby:latest を持っていなかったノードでコンテナが実行される時には、新たにイメージが pull されます。そのため、同じイメージタグを指定しているにも関わらず、実行されるイメージが異なり、問題が生じることがあります。

こういった問題を回避するためには、しばしば latest タグを用いないという対策が取られます。ちなみに、 Docker Swarm でタグは更新しないけどイメージの pull は強制したい! という場合には、 docker service update --force --image [image_name]:latest というように、 --force フラグと --image を組み合わせて用いることで強制的にリポジトリのイメージをチェックさせることができます。

b. Docker Swarm では標準で IPIP トンネリングを用いてノードを跨いだコンテナ間の通信を提供する

誤りです。Docker Swarm では標準でノードを跨いだコンテナ間の通信に VXLAN を用います。
ドキュメントの記述では以下のようにあります。

UDP port 4789 for overlay network traffic

IANA のポート割当でこのポート番号を検索すると、 4789/udp は VXLAN 向けに予約されていることが分かります。

これだけの情報では実際に Docker Swarm が VXLAN を用いているのかの判断はできないですが、実際にDocker Swarm でクラスタを作り tcpdump で確認する、「Docker Swarm IPIP」「Docker Swarm VXLAN」で調べてみることにより解答できるはずです。

c. Docker Swarm ではマネージャー(クラスタを管理するノード)と非マネージャー(コンテナを実行するノード)の役割を同一のホストに割り当てることができる

正しいです。

Docker Swarm ではノードに対してマネージャー、またはワーカーの役割が割り当てられますが、コンテナの配置は役割とは関係なく ACTIVE 状態のノードに対してコンテナを配置します。

問題文を一見すると、マネージャーと非マネージャーがあるのだから、マネージャーにコンテナが配置できないと思ってしまいがちですが、これは誤りです。

あるノードにコンテナを配置しないためには、 docker node update --availability drain [node-name] コマンドにより DRAIN 状態にノードを変更する必要があります。

参考になるドキュメントは Drain a node on the swarm です。また、ドキュメント中にて例示している docker node ls の結果では、 manager のノードが ACTIVE 状態になっており、コンテナを配置できる状態になっていることが分かります。

d. Docker Swarm では非マネージャーの数より多い数のレプリカを指定したサービスを作成できる

正しいです。

Docker Swarm では、 docker service create コマンドに --replicas n オプションを付けることで指定したコンテナ数を維持させることが可能です。
このとき、3台のノードから構成されるクラスタでレプリカ数が4のサービスを作成できるか? というのが問題の本意になります。

実際これは可能であり、特にこれを制約するような文章はドキュメントに記載されていません。StackOverFlow の質問 でもこれに関する解答があります。このとき、少なくとも1台のノードには同じサービスのコンテナが2つ以上実行されることになります。

問題とは関係がありませんが、一般的にVMやコンテナにおいて、こういった配置に関する設定は Affinity/Anti-Affinity と呼ばれる設定で制御できます。OpenStack では Affinity Policy として、Kubernetes では Node/Pod Affinity としてこれらの機能が実装されています。ちなみに Docker Swarm では実装されていません。

解答

  • c, d

採点基準

正解の選択肢をすべて選んだ場合にのみ満点の70点を与えました。

講評

回答数は46件/49チーム (93.9%), 正答数は12件(26.1%)でした。

Docker Swarm はあまり使用されているケースを見ることがなく、日本語のドキュメントも少ないため混乱してしまった方も多いかと思います。英語のドキュメントは比較的豊富であり、そちらを参考にして頂ければと思いました。

Docker におけるイメージビルドに用いる docker build コマンドでも有数にハマりやすい(主観)ポイントを問題にしたものです。


3問目

問題文

以下に示す環境でイメージをビルドしたとき、期待される docker run an_image ls -l / | grep hoge コマンドの結果は選択肢のうちどれでしょう。

# ls -l
total 16
-rw-r--r--    1 root     root            66 Aug 16 10:09 Dockerfile
-rw-r--r--    1 root     root          3072 Aug 16 10:09 hoge.tar.gz
# tar tvf hoge.tar.gz
drwxr-xr-x guest/users         0 2018-03-03 23:55:03 hoge/
-rw-r--r-- guest/users         0 2016-02-27 05:03:30 hoge/a
-rw-r--r-- guest/users         0 2016-08-28 20:32:45 hoge/b
# curl https://some_host/hoge.tar.gz > remote_hoge.tar.gz
# tar tvf remote_hoge.tar.gz
drwxr-xr-x root/root         0 2018-03-03 10:16:31 hoge/
-rw-r--r-- root/root         0 2017-03-07 10:00:00 hoge/a
-rw-r--r-- root/root         0 2017-08-26 15:37:42 hoge/b
# cat Dockerfile
FROM alpine:3.6
ADD hoge.tar.gz https://some_host/hoge.tar.gz /
# docker build -t an_image .

1.

drwxr-xr-x    1 root     root          4096 Aug 16 10:09 hoge

2.

drwxr-xr-x    1 guest    users         4096 Aug 16 10:09 hoge

3.

-rw-------    1 root     root          3072 Aug 16 10:09 hoge.tar.gz

4.

-rw-------    1 guest    users         3072 Aug 16 10:09 hoge.tar.gz

5.

drwxr-xr-x    1 guest    users         4096 Aug 16 10:09 hoge
-rw-------    1 root     root          3072 Aug 16 10:09 hoge.tar.gz

6.

drwxr-xr-x    1 root     root          4096 Aug 16 10:09 hoge
-rw-------    1 guest    users         3072 Aug 16 10:09 hoge.tar.gz

解説

tar コマンド等は環境を示すために用いており、実際にはアーカイブの中身は重要ではありません。肝となるのは docker build -t an_image . の挙動です。

Dockerfile において、 ADDCOPY と同様に、ビルド時にコンテナ外のファイルをコンテナに追加するために用いられます。

ADD の挙動は分かりづらいですが、しっかりドキュメントされています。長いですね。

解答のキーとなるのは以下の2箇所です。

  1. リモートのファイルはダウンロードされる

    If is a URL and does end with a trailing slash, then the filename is inferred from the URL and the file is downloaded to /.

    抄訳すると以下のようになります。

    <src> つまり hoge.tar.gz もしくは https://some_host/hoge.tar.gz が URL であり、かつ <dest> の末尾が / で終わるとき (今回は / のため当てはまる) ときには、ファイル名は URL を基にし、 <dest>/<URLのファイル名部分> へダウンロードされる。

    このケースに当てはまるのは https://some_host/hoge.tar.gz です。つまり、 https://some_host/hoge.tar.gz はダウンロードされ、 /hoge.tar.gz へ保存されます。

  2. ローカルのアーカイブは展開されるがリモートのアーカイブは展開されない

    If is a local tar archive in a recognized compression format (identity, gzip, bzip2 or xz) then it is unpacked as a directory. Resources from remote URLs are not decompressed.

    抄訳すると以下のようになります。

    <src> がローカルの tar アーカイブであり、認識可能な圧縮形式であるときには、それはディレクトリへ展開されます。ただし、<src> がリモートのURLである場合には展開されません。

    つまり、これはローカルの hoge.tar.gz は展開されるが、 https://some_host/hoge.tar.gz は展開されないということを言っています。

ドキュメントを基にすると、少なくとも一方の hoge.tar.gz は展開され、もう一方はされていないことが分かります。つまり、選択肢を 5 もしくは 6 に絞ることができます。

実は 5 になるのか 6 になるのかはドキュメントを読むだけでは判然としません。ただし、 ADD コマンドが取得したリモートのファイルがなんの操作もなくguest ユーザに chown されることはないだろう、ということは hoge.tar.gzroot ユーザのものなはずだ、といった推測などを基に 5 を選ぶことは可能かと思います。

実際には Docker の実行環境さえあればこの問題は簡単に(10分以下で)再現可能です。 some_host の代わりに、ローカルで Web サーバを立て、適当なアーカイブで実験してみると良いでしょう。
競技時間中であれば、 Docker 実技問題のホストで実験することも可能でした。

正解

5 です。

採点基準

正答したチームへ70点を与えました。

講評

回答数は43件/49チーム (87.8%), 正答数は13件(30.2%)でした。

選択問題では、とりあえず何かを選べば正解するかもしれません。分からなくても回答してみるのも手ではないでしょうか。

予選後のアンケートにおいて Docker の筆記問題は難しかったという回答が多く見られましたが、主にこの問題、ないしは Docker Swarm に関する問題が原因になっていると考えています。
どちらの問題も、ドキュメントを読めば正答できるように作られています。 Docker のドキュメントは文章量が多いため、的確な場所をいかに早く見つけられるかというところが分かれ目になったのではないかと考えています。